package com.keta.generate.util;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * 数据源管理工具
 * 
 * @author 00fly
 * @version [版本号, 2018-11-14]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class JdbcPool
{
    private static final Logger LOGGER = LoggerFactory.getLogger(JdbcPool.class);
    
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    
    private static DataSource dataSource = new DataSource();
    
    private JdbcPool()
    {
        super();
    }
    
    // 静态初始化 DataSource
    static
    {
        ResourceBundle config = ResourceBundle.getBundle("jdbc");
        PoolProperties properties = new PoolProperties();
        properties.setUrl(config.getString("jdbc.url"));
        properties.setUsername(config.getString("jdbc.username"));
        properties.setPassword(config.getString("jdbc.password"));
        properties.setDriverClassName(config.getString("jdbc.driver"));
        properties.setFairQueue(true);// 异步获取连接,必须将fairQueue设置为true
        properties.setJmxEnabled(true);
        properties.setTestWhileIdle(false);
        properties.setTestOnBorrow(true);
        properties.setValidationQuery("select 1");
        properties.setTestOnReturn(false);
        properties.setValidationInterval(30000);
        properties.setTimeBetweenEvictionRunsMillis(30000);
        properties.setMaxActive(100);
        properties.setInitialSize(10);
        properties.setMaxWait(10000);
        properties.setRemoveAbandonedTimeout(60);
        properties.setMinEvictableIdleTimeMillis(30000);
        properties.setMinIdle(10);
        properties.setLogAbandoned(true);
        properties.setRemoveAbandoned(true);
        properties.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
        dataSource.setPoolProperties(properties);
    }
    
    /**
     * 获取数据库连接
     * 
     * @return
     * @throws SQLException
     * @throws ExecutionException
     * @throws InterruptedException
     * @see [类、类#方法、类#成员]
     */
    public static Connection getConnection()
        throws SQLException
    {
        try
        {
            Connection connection = threadLocal.get();
            if (connection == null)
            {
                Future<Connection> future = dataSource.getConnectionAsync();
                while (!future.isDone())
                {
                    try
                    {
                        TimeUnit.MICROSECONDS.sleep(100);
                    }
                    catch (InterruptedException iex)
                    {
                        Thread.currentThread().interrupt();
                        LOGGER.error(iex.getMessage(), iex);
                    }
                }
                connection = future.get();
                threadLocal.set(connection);
            }
            LOGGER.info("★★★★申请资源: {}", connection);
            return connection;
        }
        catch (Exception e)
        {
            throw new SQLException(e.getMessage(), e.getCause());
        }
    }
    
    /**
     * 关闭 Connection
     * 
     * @see [类、类#方法、类#成员]
     */
    public static void close(Connection connection)
    {
        LOGGER.info(">>>>>>> 释放资源: {}", connection);
        try
        {
            if (connection != null)
            {
                connection.close();
            }
            threadLocal.remove();
        }
        catch (SQLException e)
        {
            LOGGER.error(e.getMessage(), e);
        }
    }
    
    /**
     * 关闭 ResultSet
     * 
     * @param rs
     * @see [类、类#方法、类#成员]
     */
    public static void close(ResultSet rs)
    {
        try
        {
            if (rs != null)
            {
                rs.close();
            }
        }
        catch (SQLException e)
        {
            LOGGER.error(e.getMessage(), e);
        }
    }
    
    /**
     * 关闭 PreparedStatement
     * 
     * @param ps
     * @see [类、类#方法、类#成员]
     */
    public static void close(PreparedStatement ps)
    {
        try
        {
            if (ps != null)
            {
                ps.close();
            }
        }
        catch (SQLException e)
        {
            LOGGER.error(e.getMessage(), e);
        }
    }
    
    /**
     * 关闭 Statement
     * 
     * @param ps
     * @see [类、类#方法、类#成员]
     */
    public static void close(Statement stmt)
    {
        try
        {
            if (stmt != null)
            {
                stmt.close();
            }
        }
        catch (SQLException e)
        {
            LOGGER.error(e.getMessage(), e);
        }
    }
    
}
